using System;

namespace SharpMud.MudLib.Metadata
{
	/// <summary>
	/// This attribute is used to define that an assembly is a MudLib - a library defining and
	/// implementing codebase specific MUD functionality
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibAttribute.
		/// Designates that the target assembly is a MudLib for the SharpMud framework.
		/// </summary>
		public MudLibAttribute()
		{
		}
	}

	/// <summary>
	/// This attribute is used to define the unique name of a MudLib that an assembly implements
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibNameAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibNameAttribute.
		/// Designates the unique name of a SharpMud MudLib.
		/// </summary>
		public MudLibNameAttribute(string mudLibName)
		{
			_MudLibName = mudLibName;
		}
		
		private string _MudLibName;

		/// <summary>
		/// The name of the target assembly's implemented MudLib
		/// </summary>
		public string MudLibName
		{
			get
			{
				return _MudLibName;
			}
		}
	}

	/// <summary>
	/// This attribute is used to define the title of the MudLib implementation of the
	/// target assembly
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibTitleAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibTitleAttribute.
		/// Designates the title of a SharpMud MudLib.
		/// </summary>
		public MudLibTitleAttribute(string mudLibTitle)
		{
			_MudLibTitle = mudLibTitle;
		}
		
		private string _MudLibTitle;
		public string MudLibTitle
		{
			get
			{
				return _MudLibTitle;
			}
		}
	}

	/// <summary>
	/// This attribute is used to describe the MudLib functionality that the target assembly
	/// implements
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibDescriptionAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibDescriptionAttribute.
		/// Provides a description of a SharpMud MudLib.
		/// </summary>
		public MudLibDescriptionAttribute(string mudLibDescription)
		{
			_MudLibDescription = mudLibDescription;
		}
		
		private string _MudLibDescription;

		/// <summary>
		/// The description of the target assembly's MudLib implementation
		/// </summary>
		public string MudLibDescription
		{
			get
			{
				return _MudLibDescription;
			}
		}
	}

	/// <summary>
	/// This attribute is used to define on an assembly the unique Guid of the MudLib it implements
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibGuidAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibGuidAttribute.
		/// Designates the unique GUID of a SharpMud MudLib.
		/// </summary>
		public MudLibGuidAttribute(string guid)
		{
			_MudLibGuid = new Guid(guid);
		}

		/// <summary>
		/// Creates an instance of the MudLibGuidAttribute.
		/// Designates the unique GUID of a SharpMud MudLib.
		/// </summary>
		public MudLibGuidAttribute(System.Guid guid)
		{
			_MudLibGuid = guid;
		}
		
		private System.Guid _MudLibGuid;

		/// <summary>
		/// The Guid of the target assembly's implemented MudLib
		/// </summary>
		public System.Guid MudLibGuid
		{
			get
			{
				return _MudLibGuid;
			}
		}
	}

	/// <summary>
	/// This attribute is used to define the version of the MudLib that the target assembly implements
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibVersionAttribute : System.Attribute
	{
		/// <summary>
		/// Creates an instance of the MudLibVersionAttribute.
		/// Designates the the version of a SharpMud MudLib. (Sometimes assembly
		/// versions and MudLib versions may not be the same. This allows for some
		/// cross-compatibility.)
		/// </summary>
		public MudLibVersionAttribute(string version)
		{
			_MudLibVersion = new System.Version(version);
		}

		/// <summary>
		/// Creates an instance of the MudLibVersionAttribute.
		/// Designates the the version of a SharpMud MudLib. (Sometimes assembly
		/// versions and MudLib versions may not be the same. This allows for some
		/// cross-compatibility.)
		/// </summary>
		public MudLibVersionAttribute(System.Version version)
		{
			_MudLibVersion = version;
		}
		
		private System.Version _MudLibVersion;

		/// <summary>
		/// The version of the MudLib that the target assembly implements
		/// </summary>
		public System.Version MudLibVersion
		{
			get
			{
				return _MudLibVersion;
			}
		}
	}

	/// <summary>
	/// This attribute is used to define the MudLibRoot (base server app execution class) of the MudLib
	/// that the target assembly implements
	/// </summary>
	[AttributeUsage(System.AttributeTargets.Assembly)]
	public sealed class MudLibRootAttribute : System.Attribute
	{
        ///// <summary>
        ///// Creates an instance of the MudLibRootAttribute.
        ///// Designates which class within an assembly is the application stub that
        ///// the overlying SharpMud framework should tie into.
        ///// </summary>
        ///// <param name="mudLibRoot">The name of the class that is the target.</param>
        //public MudLibRootAttribute(string mudLibRoot)
        //{
        //    _MudLibRoot = mudLibRoot;
        //}

		/// <summary>
		/// Creates an instance of the MudLibRootAttribute.
		/// Designates which class within an assembly is the application stub that
		/// the overlying SharpMud framework should tie into.
		/// </summary>
		/// <param name="mudLibRoot">The System.Type of the class that is the target.</param>
		public MudLibRootAttribute(System.Type mudLibRoot)
		{
			_MudLibRoot = mudLibRoot;
		}

		private System.Type _MudLibRoot;

		/// <summary>
		/// Designates which class within the target assembly is the MudLibRoot
		/// </summary>
		public System.Type MudLibRoot
		{
			get
			{
                
				return _MudLibRoot;
			}
		}
	}

    public sealed class MudLibMetadata
    {
        private System.Type _MudlibRoot;

        private MudLibMetadata(System.Type mudlibRoot) { _MudlibRoot = mudlibRoot; }

        public System.Type MudLibRoot
        {
            get
            {
                return _MudlibRoot;
            }
        }

        public System.Reflection.Assembly MudLibAssembly
        {
            get
            {
                return _MudlibRoot.Assembly;
            }
        }

        public string MudLibTitle
        {
            get
            {
                if (!this.MudLibAssembly.IsDefined(typeof(MudLib.Metadata.MudLibTitleAttribute), false))
                    return String.Empty;
                MudLibTitleAttribute mudlibTitleAttribute = (this.MudLibAssembly.GetCustomAttributes(typeof(MudLibTitleAttribute), false)[0] as MudLibTitleAttribute);
                return mudlibTitleAttribute.MudLibTitle;
            }
        }

        public string MudLibDescription
        {
            get
            {
                if (!this.MudLibAssembly.IsDefined(typeof(MudLib.Metadata.MudLibDescriptionAttribute), false))
                    return String.Empty;
                MudLibDescriptionAttribute mudlibDescriptionAttribute = (this.MudLibAssembly.GetCustomAttributes(typeof(MudLibDescriptionAttribute), false)[0] as MudLibDescriptionAttribute);
                return mudlibDescriptionAttribute.MudLibDescription;
            }
        }

        public string MudLibName
        {
            get
            {
                if (!this.MudLibAssembly.IsDefined(typeof(MudLib.Metadata.MudLibNameAttribute), false))
                    return String.Empty;
                MudLibNameAttribute mudlibNameAttribute = (this.MudLibAssembly.GetCustomAttributes(typeof(MudLibNameAttribute), false)[0] as MudLibNameAttribute);
                return mudlibNameAttribute.MudLibName;
            }
        }

#region Static Stuff
        public static MudLibMetadata FromAssembly(System.Reflection.Assembly assembly)
        {
            if (!assembly.IsDefined(typeof(MudLibAttribute),false))
                return null;

            System.Type mudlibRootType = null;
            if (assembly.IsDefined(typeof(MudLibRootAttribute),false))
            {
                mudlibRootType = ((MudLibRootAttribute)(assembly.GetCustomAttributes(typeof(MudLibRootAttribute), false)[0])).MudLibRoot;
                if (mudlibRootType == null)
                    return null;
                if (!mudlibRootType.IsSubclassOf(typeof(SharpMud.Server.App.Application)))
                    return null;
                if (mudlibRootType.IsAbstract)
                    return null;
            }
            else
            {
                foreach (System.Type t in assembly.GetTypes())
                {
                    if (t.IsSubclassOf(typeof(SharpMud.Server.App.Application)))
                    {
                        if (!t.IsAbstract)
                        {
                            mudlibRootType = t;
                            break;
                        }
                    }
                }
                if (mudlibRootType == null)
                    return null;
            }
            return new MudLibMetadata(mudlibRootType);
        }
        public static bool HasValidMudLib(System.Reflection.Assembly assembly)
        {
            if (!assembly.IsDefined(typeof(MudLibAttribute),false))
                return false;

            System.Type mudlibRootType = null;
            if (assembly.IsDefined(typeof(MudLibRootAttribute),false))
            {
                mudlibRootType = ((MudLibRootAttribute)(assembly.GetCustomAttributes(typeof(MudLibRootAttribute), false)[0])).MudLibRoot;
                if (mudlibRootType == null)
                    return false;
                if (!mudlibRootType.IsSubclassOf(typeof(SharpMud.Server.App.Application)))
                    return false;
                if (mudlibRootType.IsAbstract)
                    return false;

            }
            else
            {
                foreach (System.Type t in assembly.GetTypes())
                {
                    if (t.IsSubclassOf(typeof(SharpMud.Server.App.Application)))
                    {
                        if (!t.IsAbstract)
                        {
                            mudlibRootType = t;
                            break;
                        }
                    }
                }
                if (mudlibRootType == null)
                    return false;
            }
            return true;
        }
#endregion
    }
}
